{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c9319804",
   "metadata": {},
   "source": [
    "\n",
    "# Meta-Analysis: Synthesizing Evidence from Multiple Studies\n",
    "\n",
    "This notebook introduces meta-analysis techniques, including fixed and random effects models, meta-regression, and visualization methods like forest plots and funnel plots.\n",
    "\n",
    "## Dataset Information and Links\n",
    "\n",
    "1. **Meta-analysis Data Sources:**\n",
    "   - Example datasets for meta-analysis can be found in the `metafor` R package, which provides CSV exports: [Metafor Example Data](https://www.metafor-project.org/doku.php/data/datasets)\n",
    "   - Alternatively, use any clinical study datasets where outcomes and sample sizes are available.\n",
    "\n",
    "### Prerequisites\n",
    "\n",
    "Install the required packages before running the code:\n",
    "```bash\n",
    "pip install meta-analysis numpy pandas matplotlib seaborn\n",
    "```\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de15d26a",
   "metadata": {},
   "source": [
    "\n",
    "## Fixed Effects Meta-Analysis\n",
    "\n",
    "Fixed effects models assume that all studies share the same underlying effect size. Let's calculate the pooled effect size using inverse variance weighting.\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "029abe66",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "# Example data: Study effect sizes and variances\n",
    "data = pd.DataFrame({\n",
    "    \"Study\": [\"Study 1\", \"Study 2\", \"Study 3\"],\n",
    "    \"EffectSize\": [0.2, 0.5, 0.3],\n",
    "    \"Variance\": [0.02, 0.03, 0.01]\n",
    "})\n",
    "\n",
    "# Calculate weights (inverse variance)\n",
    "data[\"Weight\"] = 1 / data[\"Variance\"]\n",
    "\n",
    "# Pooled effect size\n",
    "pooled_effect = np.sum(data[\"EffectSize\"] * data[\"Weight\"]) / np.sum(data[\"Weight\"])\n",
    "\n",
    "# Variance of pooled effect\n",
    "pooled_variance = 1 / np.sum(data[\"Weight\"])\n",
    "\n",
    "print(f\"Pooled Effect Size (Fixed Effects): {pooled_effect:.3f}\")\n",
    "print(f\"Variance of Pooled Effect: {pooled_variance:.3f}\")\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa626681",
   "metadata": {},
   "source": [
    "\n",
    "## Random Effects Meta-Analysis\n",
    "\n",
    "Random effects models account for heterogeneity among studies. We'll use the DerSimonian and Laird method for random effects meta-analysis.\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01525ba6",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# Estimate between-study variance (tau-squared)\n",
    "Q = np.sum(data[\"Weight\"] * (data[\"EffectSize\"] - pooled_effect)**2)\n",
    "df = len(data) - 1  # Degrees of freedom\n",
    "tau_squared = max(0, (Q - df) / (np.sum(data[\"Weight\"]) - np.sum(data[\"Weight\"]**2) / np.sum(data[\"Weight\"])))\n",
    "\n",
    "# Adjust weights for random effects\n",
    "data[\"RandomWeight\"] = 1 / (data[\"Variance\"] + tau_squared)\n",
    "\n",
    "# Random effects pooled effect size\n",
    "random_effect = np.sum(data[\"EffectSize\"] * data[\"RandomWeight\"]) / np.sum(data[\"RandomWeight\"])\n",
    "\n",
    "# Variance of random effects pooled effect\n",
    "random_variance = 1 / np.sum(data[\"RandomWeight\"])\n",
    "\n",
    "print(f\"Pooled Effect Size (Random Effects): {random_effect:.3f}\")\n",
    "print(f\"Variance of Random Effects Pooled Effect: {random_variance:.3f}\")\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0600b99",
   "metadata": {},
   "source": [
    "\n",
    "## Forest Plot\n",
    "\n",
    "A forest plot visualizes individual study effects and the overall pooled effect.\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0e0174cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Forest plot\n",
    "plt.errorbar(data[\"EffectSize\"], range(len(data)), xerr=np.sqrt(data[\"Variance\"]), fmt=\"o\", label=\"Individual Studies\")\n",
    "plt.axvline(pooled_effect, color=\"red\", linestyle=\"--\", label=\"Pooled Effect (Fixed)\")\n",
    "plt.axvline(random_effect, color=\"blue\", linestyle=\"--\", label=\"Pooled Effect (Random)\")\n",
    "plt.yticks(range(len(data)), data[\"Study\"])\n",
    "plt.xlabel(\"Effect Size\")\n",
    "plt.title(\"Forest Plot\")\n",
    "plt.legend()\n",
    "plt.gca().invert_yaxis()  # Reverse y-axis for readability\n",
    "plt.show()\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66b90dce",
   "metadata": {},
   "source": [
    "\n",
    "## Funnel Plot for Publication Bias\n",
    "\n",
    "A funnel plot assesses publication bias by visualizing effect sizes versus their standard errors.\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6fc60149",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# Standard errors\n",
    "data[\"StdError\"] = np.sqrt(data[\"Variance\"])\n",
    "\n",
    "# Funnel plot\n",
    "plt.scatter(data[\"EffectSize\"], 1 / data[\"StdError\"], alpha=0.7)\n",
    "plt.axvline(pooled_effect, color=\"red\", linestyle=\"--\", label=\"Pooled Effect\")\n",
    "plt.xlabel(\"Effect Size\")\n",
    "plt.ylabel(\"Precision (1 / StdError)\")\n",
    "plt.title(\"Funnel Plot\")\n",
    "plt.legend()\n",
    "plt.show()\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49a31dab",
   "metadata": {},
   "source": [
    "\n",
    "## Meta-Regression\n",
    "\n",
    "Meta-regression examines the relationship between effect sizes and study-level covariates.\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6e7aa0b",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# Example covariate data\n",
    "data[\"SampleSize\"] = [50, 100, 150]\n",
    "\n",
    "# Regression line\n",
    "from sklearn.linear_model import LinearRegression\n",
    "\n",
    "X = data[\"SampleSize\"].values.reshape(-1, 1)\n",
    "y = data[\"EffectSize\"]\n",
    "\n",
    "model = LinearRegression().fit(X, y)\n",
    "trendline = model.predict(X)\n",
    "\n",
    "# Meta-regression plot\n",
    "plt.scatter(data[\"SampleSize\"], data[\"EffectSize\"], alpha=0.7, label=\"Studies\")\n",
    "plt.plot(data[\"SampleSize\"], trendline, color=\"red\", label=\"Trend Line\")\n",
    "plt.xlabel(\"Sample Size\")\n",
    "plt.ylabel(\"Effect Size\")\n",
    "plt.title(\"Meta-Regression Plot\")\n",
    "plt.legend()\n",
    "plt.show()\n",
    "        "
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 5
}
